package available

import (
	"container/list"
	"context"
	"errors"
	"google.golang.org/grpc"
	"sync"
	"time"
)

type SlideWindowBuilder struct {
	// 窗口大小
	size time.Duration

	queue *list.List
	rate  int64

	mu sync.Mutex
}

func NewSlideWindowBuilder(size time.Duration, rate int64) *SlideWindowBuilder {
	return &SlideWindowBuilder{
		size:  size,
		rate:  rate,
		queue: list.New(),
	}
}

func (s *SlideWindowBuilder) Build() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		s.mu.Lock()
		defer s.mu.Unlock()

		// 快路径
		if int64(s.queue.Len()) < s.rate {
			s.queue.PushBack(req)
			return handler(ctx, req)
		}
		// 慢路经
		item := s.queue.Front()
		boundary := time.Now().UnixNano() - s.size.Nanoseconds()
		for item.Value.(int64) < boundary {
			s.queue.Remove(item)
			item = s.queue.Front()
		}

		if int64(s.queue.Len()) > s.rate {
			return nil, errors.New("限流：到达上限")
		}

		s.queue.PushBack(req)
		return handler(ctx, req)
	}
}
